package client

import (
	"context"
	"fmt"
	"google.golang.org/grpc"
	"google.golang.org/grpc/connectivity"
	"google.golang.org/grpc/credentials/insecure"
	"google.golang.org/protobuf/types/known/structpb"
	"net/http"
	"sync"
	"zxs-micro-2/zxs-micro-proto/businesspb/business"
	"zxs-micro-2/zxs-micro-proto/serverfindpb/serverfind"
)

//var conn *grpc.ClientConn
//var client business.BusinessServiceClient
var clientPool map[string]*BusinessClient
var clientLock sync.RWMutex

type BusinessClient struct {
	protocol   string
	ipAddr     string
	id         string
	lock       sync.Mutex
	conn       *grpc.ClientConn
	client     business.BusinessServiceClient
	httpClient http.Client
}

func init() {
	clientPool = make(map[string]*BusinessClient)
}

func InitBusinessClient(serverStruct *serverfind.ServerStruct) {
	switch serverStruct.ServerProtocol {
	case "grpc":
		initGrpcBusinessClient(serverStruct.ServerId, serverStruct.ServerIpAddr)
	case "http":
	default:

	}
}

func initGrpcBusinessClient(id, ipAddr string) {
	bc := new(BusinessClient)
	bc.protocol = "grpc"
	bc.ipAddr = ipAddr
	bc.id = id
	err := bc.redailGrpcClient()
	if err != nil {
		panic(err)
	}
	clientLock.Lock()
	clientPool[id] = bc
	clientLock.Unlock()
}

func (bc *BusinessClient) redailGrpcClient() (err error) {
	bc.lock.Lock()
	defer bc.lock.Unlock()
	if bc.conn != nil && bc.conn.GetState() == connectivity.Ready {
		return
	}
	bc.conn, err = grpc.Dial(bc.ipAddr,
		grpc.WithTransportCredentials(insecure.NewCredentials()),
		grpc.WithDefaultServiceConfig(
			fmt.Sprintf(`{"HealthCheckConfig": {"ServiceName": "%s"}}`, "grpc.health.v1.Health")))
	if err != nil {
		return
	}
	bc.client = business.NewBusinessServiceClient(bc.conn)
	return
}

func GetClient(id string) *BusinessClient {
	clientLock.RLock()
	defer clientLock.RUnlock()
	return clientPool[id]
}

func NewStruct(m map[string]interface{}) (*structpb.Struct, error) {
	return structpb.NewStruct(m)
}

func ExecBusiness(ctx context.Context, client *BusinessClient,
	execParam, execHead map[string]interface{}, reqBs []byte) ([]byte, error) {
	client.redailGrpcClient()
	s, err := structpb.NewStruct(execParam)
	if err != nil {
		return nil, err
	}
	h, err := structpb.NewStruct(execHead)
	if err != nil {
		return nil, err
	}
	rsp, err := client.client.ExecBusiness(ctx, &business.ExecBusinessRequest{
		ReqParam: s, ReqHead: h, ReqParamBytes: reqBs,
	})
	if err != nil {
		return nil, err
	}
	return rsp.RspParam, nil
}
